#include "filesys/cache.h"
#include "devices/block.h"
#include "threads/malloc.h"
#include "devices/timer.h"
#include <stdint.h>
#include <bitmap.h>
#include <list.h>


struct cache{
  char buffer[BLCOK_DATA_SIZE];
  block_sector_t sector;
  int64_t recent_use;
  bool write;
  struct list_elem elem;
};

static struct cache **cache_table;
static struct bitmap *cache_bitmap;
static struct list cache_evict_list;

void cache_init(void){
  /* allocate memory for struct cache * cache_table*/
  cache = malloc(sizeof(struct cache*) * MAX_CACHE_SECTOR); 
  /* create bitmap structure for cache_table */
  cache_bitmap = bitmap_create(MAX_CACHE_SECTOR);
  list_init(&cache_evict_list);
}

/* allocates one cache block corresponding to SECTOR block. Allocates memory
   for cache_table entry and sets one bit in cache_bitmap to mark
   allocation status of cache. returns the index of cache_table */
size_t allocate_cache(block_sector_t sector){
  size_t cache_index = bitmap_scan_and_flip(cache_bitmap,0,1,false);
  struct cache *entry = malloc(sizeof(struct cache));
  entry->sector = sector;
  entry->recent_use = timer_ticks();
  entry->write = false;
  cache_table[cache_index] = entry;
  return cache_index;
}


/* get cache entry from cache_table by the corresponding SECTOR */
struct cache * get_cache_entry(block_sector_t sector){
  int i;
  struct cache *entry = NULL;
  for(i=0; i < MAX_CACHE_SECTOR ; i++){
    if( cache_table[i] != NULL){
      if (cache_table[i]->sector == sector)
	entry = cache_table[i];
    }
  }
  return entry;
}

static int evict_cache(int cnt){
  struct cache * oldest_entry = cache_table[0];
  int oldest_index = 0;
  struct cache * entry = NULL;
  int i,j;
  while ( cnt != 0){
    for(i=0 ; i < MAX_CACHE_SECTOR;i++){
      entry = cache_table[i];
      if(entry !=NULL){
	if (entry->recent_use < oldest_entry->recent_use){
	  oldest_entry = entry;
	  oldest_index = i;
	}
      }
    }
    list_push_back(&cache_evict_list,&oldest_entry->elem);
    cache_table[oldest_index] = NULL; 
    cnt--;
  }
}

size_t cache_write(block_sector_t sector,const void * buffer){
  struct cache *entry = get_cache_entry(sector);
  /* SECTOR not currenty mapped to cache_table. evict one entry and
     allocate SECTOR to cache_table.*/
  if(entry == NULL){
    
  }
  /* SECTOR currenty mapped to cache_table buffer to entry->data */
  else {
    
  }
  
}












